package com.synface.facerecognize.algorithm;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Handler;
import android.util.Base64;
import android.util.Log;
import com.synface.facerecognize.interfaces.FaceInterface;
import com.synface.facerecognize.library.FaceRecognizeAlgorithm;
import com.synface.utils.JSONUtils;
import com.synface.utils.Logs.Logs;
import com.synface.utils.NetUtils;

import org.json.JSONException;
import org.json.JSONObject;

public class FaceRecognize extends FaceInterface
{
  public static String sReturnCode = "";

  private final String TAG = super.getClass().getName();
  private static final int THREAD_MAX_NUM = 2;
  private static int featureLength = 1552;
  private static int currentThreadNum = 0;

  private boolean isInitSuccess = false;
  private FaceRecognizeAlgorithm mFaceRecognizeAlgorithm = null;
  private static long[] multithreadValue = new long[2];

  private static FaceRecognize instance = null;
  private Handler mHandler;
  private Context mContext;
  private String mActivationCode;
  private FaceCallback mCallback;

  public static long[] getMultithreadValue()
  {
    return multithreadValue;
  }

  public static FaceRecognize getInstance(Context context)
  {
    if (instance == null) {
      instance = new FaceRecognize(context);
    }
    return instance;
  }

  private FaceRecognize(Context context) {
    if (context != null) {
      this.mContext = context;
      this.mHandler = new Handler(context.getMainLooper());
    } else {
      throw new IllegalArgumentException("Context 不能为null");
    }
    this.mFaceRecognizeAlgorithm = new FaceRecognizeAlgorithm(context);
  }

  public FaceRecognizeAlgorithm getFaceRecognizeAlgorithm() {
    return this.mFaceRecognizeAlgorithm;
  }

  public void setActivationCode(String activationCode) {
    this.mActivationCode = activationCode;
  }

  private void successCallback()
  {
    if (this.mCallback != null)
      this.mHandler.post(new Runnable()
      {
        public void run()
        {
          FaceRecognize.this.mCallback.onSuccess();
        }
      });
  }

  private void errorCallback(final int code, final String message) {
    if(this.mCallback != null) {
      this.mHandler.post(new Runnable() {
        public void run() {
          FaceRecognize.this.mCallback.onError(code, message);
        }
      });
    }

  }

  public int SynFace_Init(long[] multithreadSupport)
  {
    int result = 0;

    if (this.isInitSuccess == true) {
      Logs.releaseLog(this.TAG, "SynFace_Init multi times !!!");
    }

    if (multithreadSupport.length > 2) {
      Logs.releaseLog(this.TAG, "SynFace_Init only support 2 thread max !!!");

      return -1;
    }

    int threadNum = 0;
    currentThreadNum = multithreadSupport.length;
    while (threadNum < multithreadSupport.length) {
      multithreadValue[threadNum] = 0L;
      ++threadNum;
    }

    Logs.releaseLog(this.TAG, "SynFace_Init begin");
    if ((this.mActivationCode != null) && (!"".equals(this.mActivationCode)))
      result = this.mFaceRecognizeAlgorithm.activatity(this.mActivationCode);
    else {
      result = this.mFaceRecognizeAlgorithm.isGranted();
    }

    if (result < 0) {
      Logs.releaseLog(this.TAG, "SynFace_Init fail:" +
        String.valueOf(result));

      return result;
    }

    result = this.mFaceRecognizeAlgorithm.loadAssetFile();
    if (result < 0) {
      Logs.releaseLog(this.TAG, "SynFace_Init fail:" + String.valueOf(result));
      return result;
    }

    result = this.mFaceRecognizeAlgorithm.init(multithreadSupport);
    Logs.releaseLog(this.TAG, "多线程初始化结果:" + String.valueOf(result));
    if (result > 0) {
      this.isInitSuccess = true;
      featureLength = result;

      threadNum = 0;
      while (threadNum < multithreadSupport.length) {
        multithreadValue[threadNum] = multithreadSupport[threadNum];
        ++threadNum;
      }
      return 0;
    }
    return result;
  }

  @Deprecated
  public void SynFace_Deinit(Context context, long currentThread)
  {
    SynFace_Deinit(currentThread);
  }

  public void SynFace_Deinit(){
    try{
      SynFace_Deinit( multithreadValue[0]);
      SynFace_Deinit( multithreadValue[1]);
    }catch (Exception e){}
  }

  public void SynFace_Deinit(long currentThread)
  {
    if (this.isInitSuccess == true) {
      Logs.releaseLog(this.TAG, "清除指定资源" + currentThread);
      int threadNum = 0;
      while (threadNum < currentThreadNum) {
        if (multithreadValue[threadNum] == currentThread) {
          multithreadValue[threadNum] = 0L;
          break;
        }
        ++threadNum;
      }

      this.mFaceRecognizeAlgorithm.deinit(currentThread);

      boolean isAllThreadExit = true;
      threadNum = 0;
      while (threadNum < currentThreadNum) {
        if (multithreadValue[threadNum] != 0L) {
          isAllThreadExit = false;
        }
        ++threadNum;
      }

      if (isAllThreadExit != true)
        return;
      this.isInitSuccess = false;
      Logs.releaseLog(this.TAG, "所有资源均卸载");
    }
  }

  @Deprecated
  public String SynFace_GetFaceFeature(Context context, Bitmap imageBitmap, long currentThread)
    throws FaceInterface.FaceException
  {
    return SynFace_GetFaceFeature(imageBitmap, currentThread);
  }

  public String SynFace_GetFaceFeature(Bitmap imageBitmap, long currentThread)
    throws FaceInterface.FaceException
  {
    if (!this.isInitSuccess) {
      throw new FaceInterface.FaceException(-31);
    }

    int threadNum = 0;
    boolean isThreadExist = false;
    while (threadNum < currentThreadNum) {
      if (multithreadValue[threadNum] == currentThread) {
        isThreadExist = true;
        break;
      }
      ++threadNum;
    }
    if ((!isThreadExist) || (currentThread == 0L)) {
      Logs.releaseLog("SynFace_GetFaceFeature", "currentThreadNum 不是init 生成的");

      throw new FaceInterface.FaceException(-3);
    }

    byte[] mFeature = new byte[featureLength];

    int imageSize = imageBitmap.getHeight() * imageBitmap.getWidth() *
      com.synface.utils.image.ImageTools.getBytesPerPixel(imageBitmap
      .getConfig());

    if (imageBitmap == null) {
      Logs.releaseLog("SynFace_GetFaceFeature", "image bitmap is null, please check imageBitmap");

      return null;
    }

    Logs.debugLog("SynFace_GetFaceFeature", "imageBitmap size is  " +
      String.valueOf(imageSize));

    Logs.debugLog("SynFace_GetFaceFeature", "bitmap.getWidth() " +
      String.valueOf(imageBitmap
      .getWidth()));
    Logs.debugLog("SynFace_GetFaceFeature", "bitmap.getHeight() " +
      String.valueOf(imageBitmap
      .getHeight()));

    int result = this.mFaceRecognizeAlgorithm.getFeature(mFeature, imageBitmap, currentThread);

    Log.e(this.TAG, "result=" + result);

    if (result > 0) {
      String base64Encrypt = Base64.encodeToString(mFeature, 2);

      Logs.releaseLog("SynFace_GetFaceFeature", "GetFaceFeature success!" + base64Encrypt
        .length());
      return base64Encrypt;
    }
    Logs.releaseLog("SynFace_GetFaceFeature", "can not get a feature from this bitmap!");

    return null;
  }

  public String SynFace_GetFaceFeature(Bitmap imageBitmap) throws FaceInterface.FaceException
  {
    return SynFace_GetFaceFeature(imageBitmap, multithreadValue[0]);
  }

  @Deprecated
  public String SynFace_GetFaceFeature(Context context, Bitmap imageBitmap) throws FaceInterface.FaceException
  {
    return SynFace_GetFaceFeature(imageBitmap, multithreadValue[0]);
  }

  @Deprecated
  public String SynFace_GetFaceFeatureByData(Context context, byte[] data, int width, int height, long currentThread) throws FaceInterface.FaceException
  {
    return SynFace_GetFaceFeatureByData(data, width, height, currentThread);
  }

  public String SynFace_GetFaceFeatureByData(byte[] data, int width, int height, long currentThread)
    throws FaceInterface.FaceException
  {
    if (!this.isInitSuccess) {
      throw new FaceInterface.FaceException( -31);
    }

    int threadNum = 0;
    boolean isThreadExist = false;
    while (threadNum < currentThreadNum) {
      if (multithreadValue[threadNum] == currentThread) {
        isThreadExist = true;
        break;
      }
      ++threadNum;
    }
    if ((!isThreadExist) || (currentThread == 0L)) {
      Logs.releaseLog("SynFace_GetFaceFeature", "currentThreadNum 不是init 生成的");

      throw new FaceInterface.FaceException( -3);
    }

    byte[] mFeature = new byte[featureLength];
    int imageSize = width * height * 4;

    if (data == null) {
      Logs.releaseLog("SynFace_GetFaceFeatureByData", "image bitmap is null, please check imageBitmap");

      return null;
    }

    Logs.debugLog("SynFace_GetFaceFeatureByData", "imageBitmap size is  " +
      String.valueOf(imageSize));

    Logs.debugLog("SynFace_GetFaceFeatureByData", "bitmap.getWidth() " +
      String.valueOf(width));

    Logs.debugLog("SynFace_GetFaceFeatureByData", "bitmap.getHeight() " +
      String.valueOf(height));

    int result = this.mFaceRecognizeAlgorithm.getFeatureByData(mFeature, data, width, height, currentThread);

    if (result > 0) {
      String base64Encrypt = Base64.encodeToString(mFeature, 2);

      Logs.i("SynFace_GetFaceFeature", "GetFaceFeature success!" + base64Encrypt
        .length());
      return base64Encrypt;
    }
    Logs.releaseLog("SynFace_GetFaceFeature", "code:" + result + " can not get a feature from this bitmap!");

    return null;
  }

  public String SynFace_GetFaceFeatureByData(byte[] data, int width, int height) throws FaceInterface.FaceException {
    return SynFace_GetFaceFeatureByData(data, width, height);
  }

  @Deprecated
  public String SynFace_GetFaceFeatureByData(Context context, byte[] data, int width, int height) throws FaceInterface.FaceException
  {
    return SynFace_GetFaceFeatureByData(data, width, height, multithreadValue[0]);
  }

  @Deprecated
  public int SynFace_CompareFeature(Context context, String feature1, String feature2, long currentThread)
    throws FaceInterface.FaceException
  {
    return SynFace_CompareFeature(feature1, feature2, currentThread);
  }

  public int SynFace_CompareFeature(String feature1, String feature2, long currentThread)
    throws FaceInterface.FaceException
  {
    if (!this.isInitSuccess) {
      throw new FaceInterface.FaceException( -31);
    }

    int threadNum = 0;
    boolean isThreadExist = false;
    while (threadNum < currentThreadNum) {
      if (multithreadValue[threadNum] == currentThread) {
        isThreadExist = true;
        break;
      }
      ++threadNum;
    }
    if ((!isThreadExist) || (currentThread == 0L)) {
      Logs.releaseLog("SynFace_GetFaceFeature", "currentThreadNum 不是init 生成的");

      throw new FaceInterface.FaceException( -3);
    }

    if ((feature1 == null) || (feature1.length() < featureLength)) {
      Logs.releaseLog("SynFace_CompareFeatureSync", "feature1 is not a complete feature !");

      return -7;
    }
    if ((feature2 == null) || (feature2.length() < featureLength)) {
      Logs.releaseLog("SynFace_CompareFeatureSync", "feature2 is not a complete feature !");

      return -7;
    }

    byte[] fea1 = Base64.decode(feature1, 2);
    byte[] fea2 = Base64.decode(feature2, 2);

    int score = this.mFaceRecognizeAlgorithm.compareFeature(fea1, fea2, currentThreadNum);

    return (int)(score / 1.27D);
  }

  public int SynFace_CompareFeature(String feature1, String feature2) throws FaceInterface.FaceException
  {
    return SynFace_CompareFeature(feature1, feature2, multithreadValue[0]);
  }

  @Deprecated
  public int SynFace_CompareFeature(Context context, String feature1, String feature2)
    throws FaceInterface.FaceException
  {
    return SynFace_CompareFeature(feature1, feature2, multithreadValue[0]);
  }

  @Deprecated
  public int SynFace_GetFaceAttr(Context context, int[] faceAttr, Bitmap bitmap, long currentThread)
    throws FaceInterface.FaceException
  {
    return SynFace_GetFaceAttr(faceAttr, bitmap, currentThread);
  }

  public int SynFace_GetFaceAttr(int[] faceAttr, Bitmap bitmap, long currentThread)
    throws FaceInterface.FaceException
  {
    if (!this.isInitSuccess) {
      throw new FaceInterface.FaceException( -31);
    }
    int threadNum = 0;
    boolean isThreadExist = false;
    while (threadNum < currentThreadNum) {
      if (multithreadValue[threadNum] == currentThread) {
        isThreadExist = true;
        break;
      }
      ++threadNum;
    }
    if ((!isThreadExist) || (currentThread == 0L)) {
      Logs.releaseLog("SynFace_GetFaceFeature", "currentThreadNum 不是init 生成的");

      throw new FaceInterface.FaceException( -3);
    }

    if ((bitmap == null) || (faceAttr == null)) {
      Logs.releaseLog("SynFace_GetFaceAttr", "bitmap is null !");
      return -7;
    }
    int result = this.mFaceRecognizeAlgorithm.getFaceAttr(faceAttr, bitmap, currentThreadNum);

    return 0;
  }

  public static abstract interface FaceCallback
  {
    public abstract void onSuccess();

    public abstract void onError(int paramInt, String paramString);
  }
}